/* $Author: dshi$ */
/* $email:  dshi7@wisc.edu$ */
module proc (/*AUTOARG*/
	        // Outputs
	        err,
	        // Inputs
	        clk, rst
	     );
   input clk;
   input rst;
   output err;

      // None of the above lines can be modified

      // OR all the err ouputs for every sub-module and assign it as this
      // err output

      // As desribed in the homeworks, use the err signal to trap corner
      // cases that you think are illegal in your statemachines


      /* your code here */
    wire    [15:0]  pc_in,pc_out;
    pc PC (  
            .rst(rst),
            .clk(clk),
            .pc_en(1'b1),
            .pc_in(pc_in),
            .pc_out(pc_out) );

    wire    [15:0]  pc_plus_2;
    alu ADDER0 (   
            .op1(pc_out),
            .op2(16'H0002),
            .aluctr(4'b0000),
            .out(pc_plus_2),
            .carry_out(),
            .zero()
            );

    wire    [15:0]  inst;
    wire    createdump;
    memory2c INST_MEM   (
            .data_out(inst),
            .data_in(),
            .addr(pc_out),
            .clk(clk),
            .rst(rst),
            .enable(1'b1),
            .wr(1'b0),
            .createdump(createdump)
            );

    wire [1:0]  regdst;
    wire [2:0]  ext;
    wire [3:0]  aluop;
    wire        regwr;
    wire        memrd;
    wire        memwr;
    wire        memtoreg;
    wire        alusrc2;
    wire [2:0]  branch;
    wire        j;
    wire        jr; 
    wire        jal; 
    wire        lbi;
    ctr CONTROL (
            .inst(inst[15:11]),
            .regdst(regdst),
            .ext(ext),
            .aluop(aluop),
            .memrd(memrd),
            .memwr(memwr),
            .memtoreg(memtoreg),
            .alusrc2(alusrc2),
            .branch(branch),
            .j(j),
            .jr(jr),
            .jal(jal),
            .createdump(createdump),
            .lbi(lbi),
            .regwr(regwr)
           );

    wire    [15:0]  rd_data1,rd_data2,wr_data;
    wire    [2:0]   wr_addr;
    assign  wr_addr =   (regdst==2'b00)?inst[4:2]
                    :   (regdst==2'b01)?inst[10:8]
                    :   ((regdst==2'b10)?inst[7:5]:3'b111);

    wire    [15:0]  wb;
    rf  RF  (
            .read1data(rd_data1),
            .read2data(rd_data2),
            .err(err),
            .clk(clk),
            .rst(rst),
            .read1regsel(inst[10:8]),
            .read2regsel(inst[7:5]),
            .writeregsel(wr_addr),
            .writedata((jal==1'b1)?pc_plus_2:wb),
            .write(regwr)   );

    wire    [15:0]  immd16;
    ext EXT (
            .immd(inst[10:0]),
            .mode(ext),
            .immd16(immd16) );

    wire    jump;
    branch  BRANCH_CTR  (
            .branch(branch),
            .j(j),
            .rs(rd_data1),
            .jump(jump) );

    wire    [15:0]  branch_addr;
    alu ADDER1  (
            .op1(pc_plus_2),
            .op2(immd16),
            .aluctr(4'b0000),
            .out(branch_addr),
            .carry_out(),
            .zero() );

    wire    [3:0]   aluctr;
    aluctr ALUCTR   (
            .aluop(aluop),
            .funct(inst[1:0]),
            .aluctr(aluctr) );

    wire    [15:0]  op2,alu_out;
    assign  op2 = (alusrc2==1'b1)?immd16:rd_data2;
    wire            alu_co,alu_zero;
    alu     ALU (
            .op1(rd_data1),
            .op2(op2),
            .aluctr(aluctr),
            .out(alu_out),
            .carry_out(alu_co),
            .zero(alu_zero) );

    assign  pc_in = (jr==1'b1)?alu_out
                :   (jump==1'b1)?branch_addr:pc_plus_2;

    wire    [15:0]  mem_out;
    memory2c DATA_MEM (
            .data_out(mem_out),
            .data_in(rd_data1),
            .addr(alu_out),
            .clk(clk),
            .rst(rst),
            .enable(memrd | memwr),
            .wr(memwr),
            .createdump(createdump)
            );
    assign  wb = (memtoreg==1'b1)?  mem_out:((lbi==1'b0)?alu_out:immd16);

   endmodule // proc
// DUMMY LINE FOR REV CONTROL :0:
